Skip to content

[codex] Board UX: priority sorting, epic cards, deferred filtering#21

Merged
Helmi merged 4 commits intomainfrom
epic/td-f66afd-board-ux
Mar 1, 2026
Merged

[codex] Board UX: priority sorting, epic cards, deferred filtering#21
Helmi merged 4 commits intomainfrom
epic/td-f66afd-board-ux

Conversation

@Helmi
Copy link
Owner

@Helmi Helmi commented Mar 1, 2026

Summary

This PR completes td-f66afd (Board UX: priority sorting, epic cards, deferred filtering) and includes a follow-up rejection fix for two UI acceptance gaps.

User impact:

  • Board columns are easier to triage because ordering is now priority-first and then recency.
  • Deferred tasks are hidden from the default board view.
  • Epics are shown as first-class cards with child counts instead of inline child expansion.
  • Closed-column progressive reveal uses the expected simple action copy.
  • Task board access is always visible from the session title bar.

Root Cause

The initial implementation passed core backend acceptance but missed two explicit frontend details called out in review:

  1. The title-bar board icon was conditionally gated behind tdStatus?.projectState?.enabled.
  2. The closed-column reveal button copy showed Show {N} older instead of the required plain Show more.

A second rejection was workflow-only: the epic was submitted while child tasks remained in_review and not yet closed.

What Changed

Backend and board behavior work (already implemented on this branch):

  • Priority-first sort and deferred filtering in TD board/list issue retrieval.
  • Epic card treatment as first-class board items with child count badge and no inline expansion.
  • Board/list UX updates for dense triage.

Targeted rejection fix in this commit:

  • Render task board icon unconditionally in the session title bar (client/src/components/TerminalSession.tsx).
  • Change closed-column progressive reveal label to exact Show more (client/src/components/TaskBoard.tsx).
  • Add frontend regression coverage for both behaviors (client/src/components/BoardUxRegression.test.ts).

Workflow completion:

  • Approved child tasks (td-ff29f1, td-c6ca47) so epic state could cascade correctly.

Validation

  • bun run test -- client/src/components/BoardUxRegression.test.ts
  • bun run test

Both passed in this branch before submission.

Notes

  • One local untracked temp file (.cacd-startup-*.sh) exists in the worktree and is intentionally not part of this PR.

Helmi added 4 commits March 1, 2026 22:45
Change listIssues() ORDER BY to P0→P3 priority then updated_at DESC.
Add hideDeferred option that filters defer_until > now. getBoard() now
passes hideDeferred:true. Covers td-628268 backend half.

5 new tests: priority sort order, deferred hide/show, board variants.
…column collapse

td-628268: StatusColumn renders flat (no groupIssuesWithChildren), issues
arrive priority-sorted from backend.

td-b21b0f: Epic cards show open child count badge (global count from tdIssues).
No inline child expansion; clicking epic opens detail modal.

td-bbc52a: IssueCard redesigned — full-width title, colored priority pill
bottom-left (P0=red, P1=orange, P2=muted, P3=dim), muted ID bottom-right.
Left border and tags removed. groupIssuesWithChildren kept for list view.

td-ff29f1: Empty columns collapse to clickable vertical strip. Closed column
shows only last-3-days by default with 'Show N older' reveal button.
Min/max-width removed; flex distributes naturally.
LayoutGrid icon button in TerminalSession title bar, before the Info button.
Visible when td is enabled for the project. One-click board access from
any session view without hunting through the sidebar.
@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly improves the Board user experience by implementing priority-based sorting and deferred task filtering, allowing users to focus on the most relevant tasks. It also refines the display of epic cards to provide a clearer overview of their child tasks. Additionally, the PR addresses two critical UI regressions, ensuring consistent visibility of the task board button and a more intuitive label for revealing closed tasks, thereby enhancing overall usability and adherence to design specifications.

Highlights

  • Board UX Enhancements: Board columns now sort issues by priority first, then by recency, making triage more efficient.
  • Deferred Task Filtering: Deferred tasks are now hidden from the default board view, reducing clutter.
  • Epic Card Treatment: Epics are displayed as first-class cards with child counts, replacing the previous inline child expansion.
  • UI Regression Fixes: The closed-column progressive reveal text was updated to 'Show more', and the task board access button is now always visible in the session title bar.
  • New Regression Tests: Added dedicated frontend regression tests to cover the UI fixes for the task board button and closed column reveal text.
  • Backend Logic Updates: Implemented backend changes in tdReader to support priority-first sorting and deferred issue filtering.
Changelog
  • client/src/components/BoardUxRegression.test.ts
    • Added new regression tests to verify the persistent task board button and the 'Show more' text for closed columns.
  • client/src/components/TaskBoard.tsx
    • Refactored issue card rendering to display epics as first-class cards with child counts.
    • Removed the inline expansion of epic children.
    • Updated the closed column progressive reveal button text from 'Show {N} older' to 'Show more'.
    • Introduced a priorityBadgeClass function for dynamic priority styling.
  • client/src/components/TerminalSession.tsx
    • Integrated a dedicated task board button into the session title bar, making it unconditionally visible.
    • Imported the LayoutGrid icon for the new task board button.
  • src/services/tdReader.test.ts
    • Added tests to confirm issues are sorted by priority first, then by updated_at.
    • Included tests to verify that deferred issues are correctly hidden when hideDeferred is enabled.
  • src/services/tdReader.ts
    • Modified the listIssues method to include a hideDeferred option, filtering out future-deferred tasks.
    • Updated the SQL query in listIssues to sort results by priority (P0-P3) and then by updated_at.
    • Applied hideDeferred: true by default in the getBoard method to exclude deferred issues from the board view.
Activity
  • The author addressed two explicit frontend details that were missed in the initial implementation: ensuring the title-bar board icon is always visible and correcting the closed-column reveal button copy.
  • The author completed workflow tasks by approving child tasks (td-ff29f1, td-c6ca47) to allow the epic state to cascade correctly.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request delivers significant UX enhancements for the task board, such as priority sorting, deferred task filtering, and improved epic card presentation. It also fixes two UI regressions related to the task board button visibility and 'Show more' text, backed by new regression tests. The backend and frontend changes are well-executed. My feedback includes one suggestion to improve code readability by replacing a magic number with its calculation for better maintainability.

if (issues.length === 0) setIsCollapsed(true)
}, [issues.length])

const threeDaysAgo = new Date(Date.now() - 3 * 86_400_000).toISOString()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using a magic number like 86_400_000 for milliseconds in a day makes the code less readable. It's better to either use the calculation directly or define a constant for it to improve clarity and maintainability.

Suggested change
const threeDaysAgo = new Date(Date.now() - 3 * 86_400_000).toISOString()
const threeDaysAgo = new Date(Date.now() - 3 * 24 * 60 * 60 * 1000).toISOString()

@claude
Copy link

claude bot commented Mar 1, 2026

Code Review — Board UX: priority sorting, epic cards, deferred filtering

Overall this is clean, well-scoped work. The backend changes in tdReader.ts are solid and the targeted fixes hit the acceptance criteria. A few issues worth addressing before merging.


Bugs

1. childCountByEpicId doesn't exclude deleted children (TaskBoard.tsx:225-229)

tdIssues.forEach(issue => {
  if (issue.parent_id && issue.status !== 'closed') {
    counts.set(issue.parent_id, (counts.get(issue.parent_id) ?? 0) + 1)
  }
})

Soft-deleted children (deleted_at != null) are still counted, so the badge can overcount. The board cards themselves filter !i.deleted_at at render time — the count map should match:

if (issue.parent_id && issue.status !== 'closed' && !issue.deleted_at) {

2. All columns start collapsed on initial load (TaskBoard.tsx:132,135-137)

const [isCollapsed, setIsCollapsed] = useState(issues.length === 0)

useEffect(() => {
  if (issues.length === 0) setIsCollapsed(true)
}, [issues.length])

tdBoardView is likely empty on first mount, so every StatusColumn initialises with isCollapsed = true. The useEffect only collapses on empty — it doesn't expand when data arrives. In practice this means the board is all collapsed tabs until the user manually expands each column. The fix is either to also expand in the effect when issues appear, or to not initialise collapsed based on async data:

// Only collapse empty columns; let populated ones start expanded
useEffect(() => {
  setIsCollapsed(issues.length === 0)
}, [issues.length])

Medium issues

3. searchIssues doesn't apply the new priority sort (tdReader.ts:370-378)

listIssues now sorts by priority-first, but searchIssues still uses ORDER BY updated_at DESC. Inconsistency will be noticeable when search results return a different order than the board. Should apply the same CASE priority ... clause.

4. BoardUxRegression.test.ts is fragile source-text matching (BoardUxRegression.test.ts:10-20)

expect(source).not.toContain('{tdStatus?.projectState?.enabled && (')

This breaks on any whitespace or formatting change, and doesn't test actual rendered behaviour. It's also coupled to process.cwd() which assumes tests always run from the project root. These are "did someone accidentally revert my change" guards, not real regression tests. If you want to keep them as a temporary safety net, that's fine — but they should eventually be replaced with actual component tests (React Testing Library render + assertion on what's visible).


Minor

5. closed_at = null issues are hidden in the 3-day filter (TaskBoard.tsx:141)

issues.filter(i => (i.closed_at ?? '') >= threeDaysAgo)

An issue in closed status with a null closed_at gets the empty-string fallback, which fails the comparison and hides the issue until "Show more" is clicked. Probably fine in practice, but worth a comment so it's not a surprise.

6. threeDaysAgo recalculates on every render (TaskBoard.tsx:139)

Move it inside a useMemo to avoid the Date.now() call on every render of StatusColumn. Low impact but free:

const threeDaysAgo = useMemo(
  () => new Date(Date.now() - 3 * 86_400_000).toISOString(),
  []
)

Positives

  • The backend deferred-filtering SQL is correct and tested well.
  • Priority CASE sort in SQL is the right approach — keeps the sort in the DB layer where it belongs.
  • getBoard() defaulting to hideDeferred: true is a clean API decision.
  • Removing the inline epic expand/collapse in the board view simplifies the component meaningfully.
  • The childCountByEpicId useMemo being computed at the TaskBoard level and passed down is the right architecture (avoids per-column redundant computation).
  • The unconditional task board button fix is correct — the "TD not enabled" empty state is the appropriate fallback.

Items 1 and 2 are the most important to address before merging. The rest are polish.

@Helmi Helmi marked this pull request as ready for review March 1, 2026 22:06
@Helmi Helmi merged commit 80d4ef8 into main Mar 1, 2026
8 checks passed
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1322d15d53

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


const threeDaysAgo = new Date(Date.now() - 3 * 86_400_000).toISOString()
const visibleIssues = (status.key === 'closed' && !showAllClosed)
? issues.filter(i => (i.closed_at ?? '') >= threeDaysAgo)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Compare closed timestamps as dates, not raw strings

The closed-column reveal logic is doing a lexical string comparison between closed_at and threeDaysAgo, but threeDaysAgo is ISO (...T...Z) while SQLite DATETIME values are typically space-separated (YYYY-MM-DD HH:MM:SS); this causes recent items on the cutoff date to be treated as older and hidden behind “Show more”. In practice, closed tasks within the last 3 days can disappear from the default view depending on timestamp format, so this should parse/normalize timestamps before comparing.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant